/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ufpb.compiladores.sintatico.impl;

import java.util.Stack;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ufpb.compiladores.lexico.LexicalTable;
import ufpb.compiladores.sintatico.Clause;
import ufpb.compiladores.sintatico.Entity;
import ufpb.compiladores.sintatico.Enviroment;
import ufpb.compiladores.sintatico.Production;
import ufpb.compiladores.sintatico.SyntacticalAnalyzer;

/**
 *
 * @author Sarah
 */
public class LexicalTableProcessor implements SyntacticalAnalyzer {

    private Enviroment env = null;
    private LexicalTable lt = null;

    public LexicalTableProcessor(Enviroment env, LexicalTable lt){

        this.env = env;
        this.lt = lt;

        //this.env.removeRecursion();
        //this.env.removeNonDeterminism();
    }

    @Override
    public void processEnviroment(Document doc, Element r) {

        this.processAll();
    }

    public static class ProductionClauseEntity {

        String prod;
        int cl;
        int ent;

        public ProductionClauseEntity(String prod, int cl, int ent){

            this.prod = prod;
            this.cl = cl;
            this.ent = ent;
        }

        public String getNameProduction(){

            return this.prod;
        }

        public int getClauseNumber(){

            return this.cl;
        }

        public int getEntityNumber(){

            return this.ent;
        }
    }

    /* Tô em dúvida se isso é aqui e assim, mas lá vai: */

    public void processAll (){

        //Criei esse getInitialProductions lá no Enviroment

        Production prodAtual = env.getInitialProduction();
        Entity[] allEntities = null;
        Clause[] allClauses = null;
        int j, linha, clausePosition=0, entityPosition=0;
        String token; String description;
        Stack pilha = new Stack<ProductionClauseEntity>();
        boolean fromStack = false;

        if(lt.hasNext()){

            for(int i=0; i<prodAtual.getClauses().length; i++){

                allClauses = prodAtual.getClauses();

                if (!fromStack) {

                    for(j=0; j<allClauses.length; j++){ //pegar a cláusula a ser processada

                        if (allClauses[j].getEntities()[0].value().equals(lt.getNext(1).getToken())){
                            break;
                        }
                    }

                for (int k=0; k<allClauses[j].getEntities().length; k++){

                    allEntities = allClauses[j].getEntities();

                    if (allEntities[k].getType() == Entity.EntityType.TOKEN){

                        if (lt.hasNext()){
                            lt.next();
                            token = lt.getCurrent().getToken();
                            linha = lt.getCurrent().getLine(); //pega a linha pra mostrar onde foi o erro, se houver
                        } else {
                            System.out.println("Fim de arquivo.");
                            return;
                        }

                        if (allEntities[k].value().equals(token)){
                            /* ok */
                        } else {
                            System.out.println("Esperado '"+allEntities[k].value()+"', recebido '"+token+"'. Linha "+linha+".");
                        }
                    }

                    else if (allEntities[k].getType() == Entity.EntityType.TYPE){

                    if (lt.hasNext()){
                            lt.next();
                            description = lt.getCurrent().getDescription();
                            linha = lt.getCurrent().getLine(); //pega a linha pra mostrar onde foi o erro, se houver
                        } else {
                            System.out.println("Fim de arquivo.");
                            return;
                        }

                        if (allEntities[k].value().equals(description)){
                            /* ok */
                        } else {
                            System.out.println("Esperado '"+allEntities[k].value()+"', recebido '"+description+"'. Linha "+linha+".");
                        }
                    }

                    else if (allEntities[k].getType() == Entity.EntityType.PRODUCTION){

                        ProductionClauseEntity pce = new ProductionClauseEntity(prodAtual.getName(), j, k);
                        pilha.push(pce);
                        prodAtual = env.getProduction(allEntities[k].value());

                        k = 0;
                        j = 0;

                        allClauses = prodAtual.getClauses();

                    }

                    else if (allEntities[k].getType() == Entity.EntityType.VOID) {
                        /* nada */
                    }
                }

            } else {

                j = clausePosition;

                for (int k=entityPosition; k<allClauses[j].getEntities().length; k++){

                    allEntities = allClauses[j].getEntities();

                    if (allEntities[k].getType() == Entity.EntityType.TOKEN){

                        if (lt.hasNext()){
                            lt.next();
                            token = lt.getCurrent().getToken();
                            linha = lt.getCurrent().getLine(); //pega a linha pra mostrar onde foi o erro, se houver
                        } else {
                            System.out.println("Fim de arquivo.");
                            return;
                        }

                        if (allEntities[k].value().equals(token)){
                            /* ok */
                        } else {
                            System.out.println("Esperado '"+allEntities[k].value()+"', recebido '"+token+"'. Linha "+linha+".");
                        }
                    }

                    else if (allEntities[k].getType() == Entity.EntityType.TYPE){

                    if (lt.hasNext()){
                            lt.next();
                            description = lt.getCurrent().getDescription();
                            linha = lt.getCurrent().getLine(); //pega a linha pra mostrar onde foi o erro, se houver
                        } else {
                            System.out.println("Fim de arquivo.");
                            return;
                        }

                        if (allEntities[k].value().equals(description)){
                            /* ok */
                        } else {
                            System.out.println("Esperado '"+allEntities[k].value()+"', recebido '"+description+"'. Linha"+linha+".");
                        }
                    }

                    else if (allEntities[k].getType() == Entity.EntityType.PRODUCTION){

                        ProductionClauseEntity pce = new ProductionClauseEntity(prodAtual.getName(), j, k);
                        pilha.push(pce);
                        prodAtual = env.getProduction(allEntities[k].value());

                        k=0;
                        j=0;

                        allClauses = prodAtual.getClauses();

                    }

                    else if (allEntities[k].getType() == Entity.EntityType.VOID) {
                        /* nada */
                    }
                }
                }

                if (!pilha.isEmpty()){

                    ProductionClauseEntity pce = (ProductionClauseEntity) pilha.pop();
                    prodAtual = env.getProduction(pce.getNameProduction());
                    clausePosition = pce.getClauseNumber()+1;
                    entityPosition = pce.getEntityNumber()+1;
                    fromStack = true;

                }

            }
        }
    }
}
